home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / gawk-3.000 / gawk-3 / gawk-3.0.0 / field.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-29  |  19.2 KB  |  792 lines

  1. /*
  2.  * field.c - routines for dealing with fields and record parsing
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991-1995 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Programming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  24.  */
  25.  
  26. #include "awk.h"
  27.  
  28. typedef void (* Setfunc) P((long, char *, long, NODE *));
  29.  
  30. static long (*parse_field) P((long, char **, int, NODE *,
  31.                  Regexp *, Setfunc, NODE *));
  32. static void rebuild_record P((void));
  33. static long re_parse_field P((long, char **, int, NODE *,
  34.                  Regexp *, Setfunc, NODE *));
  35. static long def_parse_field P((long, char **, int, NODE *,
  36.                   Regexp *, Setfunc, NODE *));
  37. static long null_parse_field P((long, char **, int, NODE *,
  38.                  Regexp *, Setfunc, NODE *));
  39. static long sc_parse_field P((long, char **, int, NODE *,
  40.                  Regexp *, Setfunc, NODE *));
  41. static long fw_parse_field P((long, char **, int, NODE *,
  42.                  Regexp *, Setfunc, NODE *));
  43. static void set_element P((long num, char * str, long len, NODE *arr));
  44. static void grow_fields_arr P((long num));
  45. static void set_field P((long num, char *str, long len, NODE *dummy));
  46.  
  47.  
  48. static char *parse_extent;    /* marks where to restart parse of record */
  49. static long parse_high_water = 0; /* field number that we have parsed so far */
  50. static long nf_high_water = 0;    /* size of fields_arr */
  51. static int resave_fs;
  52. static NODE *save_FS;        /* save current value of FS when line is read,
  53.                  * to be used in deferred parsing
  54.                  */
  55. static NODE **nodes;        /* permanent repository of field nodes */
  56. static int *FIELDWIDTHS = NULL;
  57.  
  58. NODE **fields_arr;        /* array of pointers to the field nodes */
  59. int field0_valid;        /* $(>0) has not been changed yet */
  60. int default_FS;            /* 1 when FS == " " */
  61. Regexp *FS_regexp = NULL;
  62.  
  63. /* init_fields --- set up the fields array to start with */
  64.  
  65. void
  66. init_fields()
  67. {
  68.     NODE *n;
  69.  
  70.     emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
  71.     emalloc(nodes, NODE **, sizeof(NODE *), "init_fields");
  72.     getnode(n);
  73.     *n = *Nnull_string;
  74.     n->flags |= SCALAR;
  75.     fields_arr[0] = nodes[0] = n;
  76.     parse_extent = fields_arr[0]->stptr;
  77.     save_FS = dupnode(FS_node->var_value);
  78.     field0_valid = TRUE;
  79. }
  80.  
  81. /* grow_fields --- acquire new fields as needed */
  82.  
  83. static void
  84. grow_fields_arr(num)
  85. long num;
  86. {
  87.     register int t;
  88.     register NODE *n;
  89.  
  90.     erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "grow_fields_arr");
  91.     erealloc(nodes, NODE **, (num+1) * sizeof(NODE *), "grow_fields_arr");
  92.     for (t = nf_high_water + 1; t <= num; t++) {
  93.         getnode(n);
  94.         *n = *Nnull_string;
  95.         n->flags |= SCALAR;
  96.         fields_arr[t] = nodes[t] = n;
  97.     }
  98.     nf_high_water = num;
  99. }
  100.  
  101. /* set_field --- set the value of a particular field */
  102.  
  103. /*ARGSUSED*/
  104. static void
  105. set_field(num, str, len, dummy)
  106. long num;
  107. char *str;
  108. long len;
  109. NODE *dummy;    /* not used -- just to make interface same as set_element */
  110. {
  111.     register NODE *n;
  112.  
  113.     if (num > nf_high_water)
  114.         grow_fields_arr(num);
  115.     n = nodes[num];
  116.     n->stptr = str;
  117.     n->stlen = len;
  118.     n->flags = (PERM|STR|STRING|MAYBE_NUM);
  119.     fields_arr[num] = n;
  120. }
  121.  
  122. /* rebuild_record --- Someone assigned a value to $(something).
  123.             Fix up $0 to be right */
  124.  
  125. static void
  126. rebuild_record()
  127. {
  128.     /*
  129.      * use explicit unsigned longs for lengths, in case
  130.      * a size_t isn't big enough.
  131.      */
  132.     register unsigned long tlen;
  133.     register unsigned long ofslen;
  134.     register NODE *tmp;
  135.     NODE *ofs;
  136.     char *ops;
  137.     register char *cops;
  138.     register NODE **ptr;
  139.  
  140.     tlen = 0;
  141.     ofs = force_string(OFS_node->var_value);
  142.     ofslen = ofs->stlen;
  143.     for (ptr = &fields_arr[NF]; ptr > &fields_arr[0]; ptr--) {
  144.         tmp = force_string(*ptr);
  145.         tlen += tmp->stlen;
  146.     }
  147.     tlen += (NF - 1) * ofslen;
  148.     if ((long) tlen < 0)
  149.         tlen = 0;
  150.     emalloc(ops, char *, tlen + 2, "rebuild_record");
  151.     cops = ops;
  152.     ops[0] = '\0';
  153.     for (ptr = &fields_arr[1]; ptr <= &fields_arr[NF]; ptr++) {
  154.         tmp = *ptr;
  155.         if (tmp->stlen == 1)
  156.             *cops++ = tmp->stptr[0];
  157.         else if (tmp->stlen != 0) {
  158.             memcpy(cops, tmp->stptr, tmp->stlen);
  159.             cops += tmp->stlen;
  160.         }
  161.         if (ptr != &fields_arr[NF]) {
  162.             if (ofslen == 1)
  163.                 *cops++ = ofs->stptr[0];
  164.             else if (ofslen != 0) {
  165.                 memcpy(cops, ofs->stptr, ofslen);
  166.                 cops += ofslen;
  167.             }
  168.         }
  169.     }
  170.     tmp = make_str_node(ops, tlen, ALREADY_MALLOCED);
  171.     unref(fields_arr[0]);
  172.     fields_arr[0] = tmp;
  173.     field0_valid = TRUE;
  174. }
  175.  
  176. /*
  177.  * set_record:
  178.  * setup $0, but defer parsing rest of line until reference is made to $(>0)
  179.  * or to NF.  At that point, parse only as much as necessary.
  180.  */
  181. void
  182. set_record(buf, cnt, freeold)
  183. char *buf;
  184. int cnt;
  185. int freeold;
  186. {
  187.     register int i;
  188.  
  189.     NF = -1;
  190.     for (i = 1; i <= parse_high_water; i++)
  191.         unref(fields_arr[i]);
  192.  
  193.     parse_high_water = 0;
  194.     /*
  195.      * $0 = $0 should resplit using the current value of FS, thus,
  196.      * this if is executed orthogonally to the value of freeold.
  197.      */
  198.     if (resave_fs) {
  199.         resave_fs = FALSE;
  200.         unref(save_FS);
  201.         save_FS = dupnode(FS_node->var_value);
  202.     }
  203.     if (freeold) {
  204.         unref(fields_arr[0]);
  205.         nodes[0]->stptr = buf;
  206.         nodes[0]->stlen = cnt;
  207.         nodes[0]->stref = 1;
  208.         nodes[0]->flags = (STRING|STR|PERM|MAYBE_NUM);
  209.         fields_arr[0] = nodes[0];
  210.     }
  211.     fields_arr[0]->flags |= MAYBE_NUM;
  212.     field0_valid = TRUE;
  213. }
  214.  
  215. /* reset_record --- start over again with current $0 */
  216.  
  217. void
  218. reset_record()
  219. {
  220.     (void) force_string(fields_arr[0]);
  221.     set_record(fields_arr[0]->stptr, fields_arr[0]->stlen, FALSE);
  222. }
  223.  
  224. /* set_NF --- handle what happens to $0 and fields when NF is changed */
  225.  
  226. void
  227. set_NF()
  228. {
  229.     register int i;
  230.  
  231.     NF = (long) force_number(NF_node->var_value);
  232.     if (NF > nf_high_water)
  233.         grow_fields_arr(NF);
  234.     for (i = parse_high_water + 1; i <= NF; i++) {
  235.         unref(fields_arr[i]);
  236.         fields_arr[i] = Nnull_string;
  237.     }
  238.     field0_valid = FALSE;
  239. }
  240.  
  241. /*
  242.  * re_parse_field --- parse fields using a regexp.
  243.  *
  244.  * This is called both from get_field() and from do_split()
  245.  * via (*parse_field)().  This variation is for when FS is a regular
  246.  * expression -- either user-defined or because RS=="" and FS==" "
  247.  */
  248. static long
  249. re_parse_field(up_to, buf, len, fs, rp, set, n)
  250. long up_to;    /* parse only up to this field number */
  251. char **buf;    /* on input: string to parse; on output: point to start next */
  252. int len;
  253. NODE *fs;
  254. Regexp *rp;
  255. Setfunc set;    /* routine to set the value of the parsed field */
  256. NODE *n;
  257. {
  258.     register char *scan = *buf;
  259.     register long nf = parse_high_water;
  260.     register char *field;
  261.     register char *end = scan + len;
  262.  
  263.     if (up_to == HUGE)
  264.         nf = 0;
  265.     if (len == 0)
  266.         return nf;
  267.  
  268.     if (RS_is_null && default_FS)
  269.         while (scan < end && (*scan == ' ' || *scan == '\t' || *scan == '\n'))
  270.             scan++;
  271.     field = scan;
  272.     while (scan < end
  273.            && research(rp, scan, 0, (end - scan), TRUE) != -1
  274.            && nf < up_to) {
  275.         if (REEND(rp, scan) == RESTART(rp, scan)) {   /* null match */
  276.             scan++;
  277.             if (scan == end) {
  278.                 (*set)(++nf, field, (long)(scan - field), n);
  279.                 up_to = nf;
  280.                 break;
  281.             }
  282.             continue;
  283.         }
  284.         (*set)(++nf, field,
  285.                (long)(scan + RESTART(rp, scan) - field), n);
  286.         scan += REEND(rp, scan);
  287.         field = scan;
  288.         if (scan == end)    /* FS at end of record */
  289.             (*set)(++nf, field, 0L, n);
  290.     }
  291.     if (nf != up_to && scan < end) {
  292.         (*set)(++nf, scan, (long)(end - scan), n);
  293.         scan = end;
  294.     }
  295.     *buf = scan;
  296.     return (nf);
  297. }
  298.  
  299. /*
  300.  * def_parse_field --- default field parsing.
  301.  *
  302.  * This is called both from get_field() and from do_split()
  303.  * via (*parse_field)().  This variation is for when FS is a single space
  304.  * character.
  305.  */
  306. static long
  307. def_parse_field(up_to, buf, len, fs, rp, set, n)
  308. long up_to;    /* parse only up to this field number */
  309. char **buf;    /* on input: string to parse; on output: point to start next */
  310. int len;
  311. NODE *fs;
  312. Regexp *rp;
  313. Setfunc set;    /* routine to set the value of the parsed field */
  314. NODE *n;
  315. {
  316.     register char *scan = *buf;
  317.     register long nf = parse_high_water;
  318.     register char *field;
  319.     register char *end = scan + len;
  320.     char sav;
  321.  
  322.     if (up_to == HUGE)
  323.         nf = 0;
  324.     if (len == 0)
  325.         return nf;
  326.  
  327.     /*
  328.      * Nasty special case. If FS set to "", return whole record
  329.      * as first field. This is not worth a separate function.
  330.      */
  331.     if (fs->stlen == 0) {
  332.         (*set)(++nf, *buf, len, n);
  333.         *buf += len;
  334.         return nf;
  335.     }
  336.  
  337.     /* before doing anything save the char at *end */
  338.     sav = *end;
  339.     /* because it will be destroyed now: */
  340.  
  341.     *end = ' ';    /* sentinel character */
  342.     for (; nf < up_to; scan++) {
  343.         /*
  344.          * special case:  fs is single space, strip leading whitespace 
  345.          */
  346.         while (scan < end && (*scan == ' ' || *scan == '\t'))
  347.             scan++;
  348.         if (scan >= end)
  349.             break;
  350.         field = scan;
  351.         while (*scan != ' ' && *scan != '\t')
  352.             scan++;
  353.         (*set)(++nf, field, (long)(scan - field), n);
  354.         if (scan == end)
  355.             break;
  356.     }
  357.  
  358.     /* everything done, restore original char at *end */
  359.     *end = sav;
  360.  
  361.     *buf = scan;
  362.     return nf;
  363. }
  364.  
  365. /*
  366.  * null_parse_field --- each character is a separate field
  367.  *
  368.  * This is called both from get_field() and from do_split()
  369.  * via (*parse_field)().  This variation is for when FS is the null string.
  370.  */
  371. static long
  372. null_parse_field(up_to, buf, len, fs, rp, set, n)
  373. long up_to;    /* parse only up to this field number */
  374. char **buf;    /* on input: string to parse; on output: point to start next */
  375. int len;
  376. NODE *fs;
  377. Regexp *rp;
  378. Setfunc set;    /* routine to set the value of the parsed field */
  379. NODE *n;
  380. {
  381.     register char *scan = *buf;
  382.     register long nf = parse_high_water;
  383.     register char *end = scan + len;
  384.  
  385.     if (up_to == HUGE)
  386.         nf = 0;
  387.     if (len == 0)
  388.         return nf;
  389.  
  390.     for (; nf < up_to && scan < end; scan++)
  391.         (*set)(++nf, scan, 1L, n);
  392.  
  393.     *buf = scan;
  394.     return nf;
  395. }
  396.  
  397. /*
  398.  * sc_parse_field --- single character field separator
  399.  *
  400.  * This is called both from get_field() and from do_split()
  401.  * via (*parse_field)().  This variation is for when FS is a single character
  402.  * other than space.
  403.  */
  404. static long
  405. sc_parse_field(up_to, buf, len, fs, rp, set, n)
  406. long up_to;    /* parse only up to this field number */
  407. char **buf;    /* on input: string to parse; on output: point to start next */
  408. int len;
  409. NODE *fs;
  410. Regexp *rp;
  411. Setfunc set;    /* routine to set the value of the parsed field */
  412. NODE *n;
  413. {
  414.     register char *scan = *buf;
  415.     register char fschar;
  416.     register long nf = parse_high_water;
  417.     register char *field;
  418.     register char *end = scan + len;
  419.     int onecase;
  420.     char sav;
  421.  
  422.     if (up_to == HUGE)
  423.         nf = 0;
  424.     if (len == 0)
  425.         return nf;
  426.  
  427.     if (RS_is_null && fs->stlen == 0)
  428.         fschar = '\n';
  429.     else
  430.         fschar = fs->stptr[0];
  431.  
  432.     onecase = (IGNORECASE && isalpha(fschar));
  433.     if (onecase)
  434.         fschar = casetable[fschar];
  435.  
  436.     /* before doing anything save the char at *end */
  437.     sav = *end;
  438.     /* because it will be destroyed now: */
  439.     *end = fschar;    /* sentinel character */
  440.  
  441.     for (; nf < up_to;) {
  442.         field = scan;
  443.         if (onecase) {
  444.             while (casetable[*scan] != fschar)
  445.                 scan++;
  446.         } else {
  447.             while (*scan != fschar)
  448.                 scan++;
  449.         }
  450.         (*set)(++nf, field, (long)(scan - field), n);
  451.         if (scan == end)
  452.             break;
  453.         scan++;
  454.         if (scan == end) {    /* FS at end of record */
  455.             (*set)(++nf, field, 0L, n);
  456.             break;
  457.         }
  458.     }
  459.  
  460.     /* everything done, restore original char at *end */
  461.     *end = sav;
  462.  
  463.     *buf = scan;
  464.     return nf;
  465. }
  466.  
  467. /*
  468.  * fw_parse_field --- field parsing using FIELDWIDTHS spec
  469.  *
  470.  * This is called both from get_field() and from do_split()
  471.  * via (*parse_field)().  This variation is for fields are fixed widths.
  472.  */
  473. static long
  474. fw_parse_field(up_to, buf, len, fs, rp, set, n)
  475. long up_to;    /* parse only up to this field number */
  476. char **buf;    /* on input: string to parse; on output: point to start next */
  477. int len;
  478. NODE *fs;
  479. Regexp *rp;
  480. Setfunc set;    /* routine to set the value of the parsed field */
  481. NODE *n;
  482. {
  483.     register char *scan = *buf;
  484.     register long nf = parse_high_water;
  485.     register char *end = scan + len;
  486.  
  487.     if (up_to == HUGE)
  488.         nf = 0;
  489.     if (len == 0)
  490.         return nf;
  491.     for (; nf < up_to && (len = FIELDWIDTHS[nf+1]) != -1; ) {
  492.         if (len > end - scan)
  493.             len = end - scan;
  494.         (*set)(++nf, scan, (long) len, n);
  495.         scan += len;
  496.     }
  497.     if (len == -1)
  498.         *buf = end;
  499.     else
  500.         *buf = scan;
  501.     return nf;
  502. }
  503.  
  504. /* get_field --- return a particular $n */
  505.  
  506. NODE **
  507. get_field(requested, assign)
  508. register long requested;
  509. Func_ptr *assign;    /* this field is on the LHS of an assign */
  510. {
  511.     /*
  512.      * if requesting whole line but some other field has been altered,
  513.      * then the whole line must be rebuilt
  514.      */
  515.     if (requested == 0) {
  516.         if (! field0_valid) {
  517.             /* first, parse remainder of input record */
  518.             if (NF == -1) {
  519.                 NF = (*parse_field)(HUGE-1, &parse_extent,
  520.                         fields_arr[0]->stlen -
  521.                     (parse_extent - fields_arr[0]->stptr),
  522.                         save_FS, FS_regexp, set_field,
  523.                     (NODE *) NULL);
  524.                 parse_high_water = NF;
  525.             }
  526.             rebuild_record();
  527.             reset_record();    /* clear out fields array */
  528.         }
  529.         if (assign != NULL)
  530.             *assign = reset_record;
  531.         return &fields_arr[0];
  532.     }
  533.  
  534.     /* assert(requested > 0); */
  535.  
  536.     if (assign != NULL)
  537.         field0_valid = FALSE;        /* $0 needs reconstruction */
  538.  
  539.     if (requested <= parse_high_water)    /* already parsed this field */
  540.         return &fields_arr[requested];
  541.  
  542.     if (NF == -1) {    /* have not yet parsed to end of record */
  543.         /*
  544.          * parse up to requested fields, calling set_field() for each,
  545.          * saving in parse_extent the point where the parse left off
  546.          */
  547.         if (parse_high_water == 0)    /* starting at the beginning */
  548.             parse_extent = fields_arr[0]->stptr;
  549.         parse_high_water = (*parse_field)(requested, &parse_extent,
  550.              fields_arr[0]->stlen - (parse_extent - fields_arr[0]->stptr),
  551.              save_FS, FS_regexp, set_field, (NODE *) NULL);
  552.  
  553.         /*
  554.          * if we reached the end of the record, set NF to the number of
  555.          * fields so far.  Note that requested might actually refer to
  556.          * a field that is beyond the end of the record, but we won't
  557.          * set NF to that value at this point, since this is only a
  558.          * reference to the field and NF only gets set if the field
  559.          * is assigned to -- this case is handled below
  560.          */
  561.         if (parse_extent == fields_arr[0]->stptr + fields_arr[0]->stlen)
  562.             NF = parse_high_water;
  563.         if (requested == HUGE-1)    /* HUGE-1 means set NF */
  564.             requested = parse_high_water;
  565.     }
  566.     if (parse_high_water < requested) { /* requested beyond end of record */
  567.         if (assign != NULL) {    /* expand record */
  568.             register int i;
  569.  
  570.             if (requested > nf_high_water)
  571.                 grow_fields_arr(requested);
  572.  
  573.             /* fill in fields that don't exist */
  574.             for (i = parse_high_water + 1; i <= requested; i++)
  575.                 fields_arr[i] = Nnull_string;
  576.  
  577.             NF = requested;
  578.             parse_high_water = requested;
  579.         } else
  580.             return &Nnull_string;
  581.     }
  582.  
  583.     return &fields_arr[requested];
  584. }
  585.  
  586. /* set_element --- set an array element, used by do_split() */
  587.  
  588. static void
  589. set_element(num, s, len, n)
  590. long num;
  591. char *s;
  592. long len;
  593. NODE *n;
  594. {
  595.     register NODE *it;
  596.  
  597.     it = make_string(s, len);
  598.     it->flags |= MAYBE_NUM;
  599.     *assoc_lookup(n, tmp_number((AWKNUM) (num))) = it;
  600. }
  601.  
  602. /* do_split --- implement split(), semantics are same as for field splitting */
  603.  
  604. NODE *
  605. do_split(tree)
  606. NODE *tree;
  607. {
  608.     NODE *t1, *t2, *t3, *tmp;
  609.     NODE *fs;
  610.     char *s;
  611.     long (*parseit) P((long, char **, int, NODE *,
  612.              Regexp *, Setfunc, NODE *));
  613.     Regexp *rp = NULL;
  614.  
  615.  
  616.     /*
  617.      * do dupnode(), to avoid problems like
  618.      *    x = split(a[1], a, "blah")
  619.      * since we assoc_clear the array. gack.
  620.      * this also gives us complete call by value semantics.
  621.      */
  622.     tmp = tree_eval(tree->lnode);
  623.     t1 = dupnode(tmp);
  624.     free_temp(tmp);
  625.  
  626.     t2 = tree->rnode->lnode;
  627.     t3 = tree->rnode->rnode->lnode;
  628.  
  629.     (void) force_string(t1);
  630.  
  631.     if (t2->type == Node_param_list)
  632.         t2 = stack_ptr[t2->param_cnt];
  633.     if (t2->type != Node_var && t2->type != Node_var_array)
  634.         fatal("second argument of split is not an array");
  635.     assoc_clear(t2);
  636.  
  637.     if (t3->re_flags & FS_DFLT) {
  638.         parseit = parse_field;
  639.         fs = force_string(FS_node->var_value);
  640.         rp = FS_regexp;
  641.     } else {
  642.         tmp = force_string(tree_eval(t3->re_exp));
  643.         if (tmp->stlen == 0)
  644.             parseit = null_parse_field;
  645.         else if (tmp->stlen == 1) {
  646.             if (tmp->stptr[0] == ' ')
  647.                 parseit = def_parse_field;
  648.             else
  649.                 parseit = sc_parse_field;
  650.         } else {
  651.             parseit = re_parse_field;
  652.             rp = re_update(t3);
  653.         }
  654.         fs = tmp;
  655.     }
  656.  
  657.     s = t1->stptr;
  658.     tmp = tmp_number((AWKNUM) (*parseit)(HUGE, &s, (int) t1->stlen,
  659.                          fs, rp, set_element, t2));
  660.     unref(t1);
  661.     free_temp(t3);
  662.     return tmp;
  663. }
  664.  
  665. /* set_FIELDWIDTHS --- handle an assignment to FIELDWIDTHS */
  666.  
  667. void
  668. set_FIELDWIDTHS()
  669. {
  670.     register char *scan;
  671.     char *end;
  672.     register int i;
  673.     static int fw_alloc = 1;
  674.     static int warned = FALSE;
  675.     extern double strtod();
  676.  
  677.     if (do_lint && ! warned) {
  678.         warned = TRUE;
  679.         warning("use of FIELDWIDTHS is a gawk extension");
  680.     }
  681.     if (do_traditional)    /* quick and dirty, does the trick */
  682.         return;
  683.  
  684.     /*
  685.      * If changing the way fields are split, obey least-suprise
  686.      * semantics, and force $0 to be split totally.
  687.      */
  688.     if (fields_arr != NULL)
  689.         (void) get_field(HUGE - 1, 0);
  690.  
  691.     parse_field = fw_parse_field;
  692.     scan = force_string(FIELDWIDTHS_node->var_value)->stptr;
  693.     end = scan + 1;
  694.     if (FIELDWIDTHS == NULL)
  695.         emalloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
  696.     FIELDWIDTHS[0] = 0;
  697.     for (i = 1; ; i++) {
  698.         if (i >= fw_alloc) {
  699.             fw_alloc *= 2;
  700.             erealloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
  701.         }
  702.         FIELDWIDTHS[i] = (int) strtod(scan, &end);
  703.         if (end == scan)
  704.             break;
  705.         scan = end;
  706.     }
  707.     FIELDWIDTHS[i] = -1;
  708. }
  709.  
  710. void
  711. set_FS_if_not_FIELDWIDTHS()
  712. {
  713.     if (parse_field != fw_parse_field)
  714.         set_FS();
  715. }
  716.  
  717. /* set_FS --- handle things when FS is assigned to */
  718.  
  719. void
  720. set_FS()
  721. {
  722.     char buf[10];
  723.     NODE *fs;
  724.     static NODE *save_fs = NULL;
  725.     static NODE *save_rs = NULL;
  726.  
  727.     /*
  728.      * If changing the way fields are split, obey least-suprise
  729.      * semantics, and force $0 to be split totally.
  730.      */
  731.     if (fields_arr != NULL)
  732.         (void) get_field(HUGE - 1, 0);
  733.  
  734.     if (save_fs && cmp_nodes(FS_node->var_value, save_fs) == 0
  735.      && save_rs && cmp_nodes(RS_node->var_value, save_rs) == 0)
  736.         return;
  737.     unref(save_fs);
  738.     save_fs = dupnode(FS_node->var_value);
  739.     unref(save_rs);
  740.     save_rs = dupnode(RS_node->var_value);
  741.     resave_fs = TRUE;
  742.       buf[0] = '\0';
  743.       default_FS = FALSE;
  744.       if (FS_regexp) {
  745.         refree(FS_regexp);
  746.         FS_regexp = NULL;
  747.     }
  748.     fs = force_string(FS_node->var_value);
  749.     if (! do_traditional && fs->stlen == 0)
  750.         parse_field = null_parse_field;
  751.     else if (fs->stlen > 1)
  752.         parse_field = re_parse_field;
  753.     else if (RS_is_null) {
  754.         parse_field = sc_parse_field;
  755.         if (fs->stlen == 1) {
  756.             if (fs->stptr[0] == ' ') {
  757.                 default_FS = TRUE;
  758.                 strcpy(buf, "[ \t\n]+");
  759.             } else if (fs->stptr[0] != '\n')
  760.                 sprintf(buf, "[%c\n]", fs->stptr[0]);
  761.         }
  762.     } else {
  763.         parse_field = def_parse_field;
  764.         if (fs->stptr[0] == ' ' && fs->stlen == 1)
  765.             default_FS = TRUE;
  766.         else if (fs->stptr[0] != ' ' && fs->stlen == 1) {
  767.             if (! IGNORECASE)
  768.                 parse_field = sc_parse_field;
  769.             else if (fs->stptr[0] == '\\')
  770.                 /* yet another special case */
  771.                 strcpy(buf, "[\\\\]");
  772.             else
  773.                 sprintf(buf, "[%c]", fs->stptr[0]);
  774.         }
  775.     }
  776.     if (buf[0] != '\0') {
  777.         FS_regexp = make_regexp(buf, strlen(buf), IGNORECASE, TRUE);
  778.         parse_field = re_parse_field;
  779.     } else if (parse_field == re_parse_field) {
  780.         FS_regexp = make_regexp(fs->stptr, fs->stlen, IGNORECASE, TRUE);
  781.     } else
  782.         FS_regexp = NULL;
  783. }
  784.  
  785. /* using_fieldwidths --- is FS or FIELDWIDTHS in use? */
  786.  
  787. int
  788. using_fieldwidths()
  789. {
  790.     return     parse_field == fw_parse_field;
  791. }
  792.